/**
 * 多线程demo 
 * g++ ./demo_multi_thread.cpp -std=c++11 -lpthread -o multi_thread
*/
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>
#include <iostream>
#include <csignal>

#include <unistd.h>
#include <stdio.h>
#include <errno.h>

template <typename T>
class MultiThreadDemo { 
  public:
    MultiThreadDemo(T origin_val) 
      : sub_thread1_handle_(nullptr),
        start_flag_(false),
        shared_resource_(origin_val) {
      std::signal(SIGINT, SignalKeyCallback);
      sub_thread1_handle_ = new std::thread(Sub1Thread, this);
      sub_thread2_handle_ = new std::thread(Sub2Thread, this);
      start_flag_ = true;
      
    }

    ~MultiThreadDemo() {
      // 退出时，需要将子线程退出
      start_flag_ = false;
      if ((sub_thread1_handle_ != nullptr) && sub_thread1_handle_->joinable()) {
        sub_thread1_handle_->join();
        delete sub_thread1_handle_;
        sub_thread1_handle_ = nullptr;
      }

      if ((sub_thread2_handle_ != nullptr) && sub_thread2_handle_->joinable()) {
        sub_thread2_handle_->join();
        delete sub_thread2_handle_;
        sub_thread2_handle_ = nullptr;
      }
    }

    static void SignalKeyCallback(int signal) {
      if (signal == SIGINT) {
        std::cout << "end multi thread signal:" << signal << std::endl;
        FILE *fp = fopen("./test.log", "a+");
        fprintf(fp, "multi thread handle game over!\n");
        fclose(fp);
        exit(EXIT_SUCCESS);
      }
    }
    
    void MainThread() {
      {
        std::lock_guard<std::mutex> lg(mutex_lock_);
        shared_resource_++;
        std::cout << "thread1: " << (int)shared_resource_ << std::endl;
        FILE *fp = fopen("./test.log", "a+");
        fprintf(fp, "Thread1:in:%ld\n", (long)shared_resource_);
        fclose(fp);
      }
      sleep(1);
    }

    static void Sub1Thread(void* arg) {
      MultiThreadDemo* obj = (MultiThreadDemo*)arg;
      while (obj->start_flag_.load()) {
        {
          std::lock_guard<std::mutex> lg(obj->mutex_lock_);
          obj->shared_resource_++;
          std::cout << "thread2: " << (int)obj->shared_resource_ << std::endl;
          FILE *fp = fopen("./test.log", "a+");
          fprintf(fp, "Thread2:in:%ld\n", (long)obj->shared_resource_);
          fclose(fp);
        }
        sleep(1);
      }
    }

    static void Sub2Thread(void* arg) {
      MultiThreadDemo* obj = (MultiThreadDemo*)arg;
      while (obj->start_flag_.load()) {
        {
          std::lock_guard<std::mutex> lg(obj->mutex_lock_);
          obj->shared_resource_++;
          std::cout << "thread3: " << (int)obj->shared_resource_ << std::endl;
          FILE *fp = fopen("./test.log", "a+");
          fprintf(fp, "Thread3:in:%ld\n", (long)obj->shared_resource_);
          fclose(fp);
        }
        sleep(1);
      }
    }

  private:
    std::thread* sub_thread1_handle_;
    std::thread* sub_thread2_handle_;
    std::atomic<bool> start_flag_;
    std::mutex mutex_lock_;
    T shared_resource_;
};


int main(int argc, char** argv) {

  MultiThreadDemo<uint8_t> demo(200);

  while (1) {
    demo.MainThread();
  }

  return 0;
}